#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::programme() {
// <programme> ::= debut <seqInst> fin <EOF>

	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::seqInst() {
// <seqInst> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="si" || ls.getSymCour()=="tantque" || ls.getSymCour()=="repeter" || ls.getSymCour() == "pour" || ls.getSymCour()=="lire" || ls.getSymCour()=="ecrire");
	// tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::inst() {
// <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instPour> | <instLire> | <instEcrire>
	if (ls.getSymCour() == "si") {
		instSi();
	} else if(ls.getSymCour() == "tantque") {
		instTq();
	} else if(ls.getSymCour() == "repeter") {
		instRepeter();
	} else if(ls.getSymCour() == "pour") {
		instPour();
	} else if(ls.getSymCour() == "lire") {
		instLire();
	} else if(ls.getSymCour() == "ecrire") {
		instEcrire();	
	} else {
		affectation();
	}	
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instSi() {
//<instSi> ::= si ( <expEt> ) <seqInst> { sinonsi ( <expEt> ) <seqInst> } [ sinon <seqInst> ] finsi
	sauterSymCour("si");
	if (ls.getSymCour()=="(") {
		ls.suivant();
		expEt();
		sauterSymCour(")");
	} else {
		erreur("<instSi>");
	}

	seqInst();
	
	// sinonsi
	while(ls.getSymCour() == "sinonsi") {

		sauterSymCour("sinonsi");

		if (ls.getSymCour()=="(") {
			ls.suivant();
			expEt();
			sauterSymCour(")");
		} else {
			erreur("<instSinonsi>");
		}

		seqInst();
	}

	// sinon
	if(ls.getSymCour()=="sinon"){
		sauterSymCour("sinon");
		seqInst();
	}
	
	// finsi
	if(ls.getSymCour()=="finsi"){
		sauterSymCour("finsi");
	} else {
		erreur("<intFinsi>");
	}

}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instTq() {
// <instTq> ::= tantque ( <expEt> ) <seqInst> fintantque

	sauterSymCour("tantque");
	if (ls.getSymCour()=="(") {
		ls.suivant();
		expEt();
		sauterSymCour(")");
	} else {
		erreur("<instTq>");
	}

	seqInst();

	// fintantque
	if(ls.getSymCour()=="fintantque"){
		sauterSymCour("fintantque");
	} else {
		erreur("<finTq>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instRepeter() {
// <instRepeter> ::= repeter <seqInst> jusqua ( <expEt> )
	sauterSymCour("repeter");
	
	seqInst();

	// jusqua
	if(ls.getSymCour()=="jusqua"){
		sauterSymCour("jusqua");

		if (ls.getSymCour()=="(") {
			ls.suivant();
			expEt();
			sauterSymCour(")");
		} else {
			erreur("<instJusqua>");
		}

	} else {
		erreur("<instRepeter>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instPour() {
// <instPour> ::= pour (<affectation> ; <expEt> ; <affectation> ) <seqInst> finpour
	sauterSymCour("pour");

	// pour
	if(ls.getSymCour()=="("){
		ls.suivant();

		affectation();
		sauterSymCour(";");

		expEt();
		sauterSymCour(";");
		affectation();
		sauterSymCour(")");
	} else {
		erreur("<instPour>");
	}

	seqInst();

	if(ls.getSymCour()=="finpour"){

		sauterSymCour("finpour");
	} else {
		erreur("<finpour>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instLire() {
// <instLire> ::= lire ( <variable> )
	sauterSymCour("lire");
	if (ls.getSymCour()=="(") {
		ls.suivant();
		ts.chercheAjoute(ls.getSymCour());
		sauterSymCour("<VARIABLE>");
		sauterSymCour(")");
	} else {
		erreur("<instLire>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instEcrire() {
// <instEcrire> ::= ecrire ( <expression> | <chaine> )
	sauterSymCour("ecrire");
	if (ls.getSymCour()=="(") {
		ls.suivant();
		if(ls.getSymCour() == "<CHAINE>"){
			ts.chercheAjoute(ls.getSymCour());
			ls.suivant();
		} else {
			expression();
		}
		sauterSymCour(")");
	} else {
		erreur("<instEcrire>");
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::affectation() {
// <affectation> ::= <variable> = <expression>

	//sauterSymCour("<VARIABLE>");
	testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	expression();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expression() {
// <expression> ::= <terme> { <opAdd> <terme> }

	terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		opAdd();
		terme();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::terme() {
//  <terme> ::= <facteur> { <opMult> facteur> }
	
	facteur();
	while(ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		opMult();
		facteur();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::facteur() {
// <facteur> ::= <entier> | <chaine> | <variable> | <opUnaire> <expEt> | ( <expEt> )
	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>" || ls.getSymCour()=="<CHAINE>") {
		ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} else if (ls.getSymCour()=="-" || ls.getSymCour()=="non") {
		opUnaire();
		expEt();
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		expEt();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opAdd()
// <opAdd> ::= + | -
{
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
		ls.suivant();
	else
		erreur("<opAdd>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opMult()
// <opMult> ::= * | /
{
	if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
		ls.suivant();
	else
		erreur("<opMult>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expEt()
// <expEt> ::= <expOu> { <opEt> <expOu> }
{
	expOu();
	while(ls.getSymCour()=="et") {
		opEt();
		expOu();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expOu()
// <expOu> ::= <relation> { <opOu> <relation> }
{
	relation();
	while(ls.getSymCour()=="ou") {
		opOu();
		relation();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opEt()
// <opEt> ::= et
{
	if (ls.getSymCour()=="et")
		ls.suivant();
	else
		erreur("<opEt>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opOu()
// <opOu> ::= ou
{
	if (ls.getSymCour()=="ou")
		ls.suivant();
	else
		erreur("<opOu>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::relation()
// <relation> ::= <expression> { <opRel> <expression> }
{
	expression();
	while(ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=") {
		opRel();
		expression();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opRel()
// <opRel> ::= == | != | < | <= | > | >=
{
	if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=")
		ls.suivant();
	else
		erreur("<opRel>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opUnaire()
// <opUnaire> ::= - | non
{
	if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
		ls.suivant();
	else
		erreur("<opUnaire>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
